const XML_TYPE = 'xml',
  KEYVALUE_TYPE = 'keyvalue',
  DEFAULT_ENCODE = 'utf-8';

// var StringUtil = require(UTIL + 'StringUtil');
// var CertificateCoder = require(UTIL + 'CertificateCoder');
// var ConfUtil = require(UTIL + 'ConfUtil');

var BASE_DIR = __dirname + '/../';
var StringUtil = require('./StringUtil.js');
var CertificateCoder = require('./CertificateCoder.js');
var ConfUtil = require('./ConfUtil.js');
var Base64Util = require('./Base64Util.js');

/**
 * 对字符串进行签名
 * 1.支持xml签名
 * 2.支持keyvalue签名
 * @param  {[string]} signStr [被签字符串]
 * @return {[string]}        [签名字符串]
 */
// exports.sign = function(signStr) {
exports.sign = function(signStr) {
  if (StringUtil.isBlank(signStr)) {
    throw new Error('不支持空字符串签名');
  }
  try {
    var valueType = checkSignStr(signStr); //判断类型
    if (valueType === XML_TYPE) {
      signStr = StringUtil.replaceXMLBlank(signStr); // 格式化为一行
      var header = StringUtil.getValueByTag('Header', signStr);
      var body = StringUtil.getValueByTag('Body', signStr);
      var sb = '<Header>' + header + '</Header>|<Body>' + body + '</Body>';
      ConfUtil.init('../config/upay.properties');
      CertificateCoder.init(BASE_DIR + ConfUtil.get('keystore.priKeyPath'), BASE_DIR + ConfUtil.get('keystore.pubKeyPath'));
      var signByte = CertificateCoder.sign(sb);
      var signReturn = Base64Util.encode(signByte);
      var cerId = CertificateCoder.getSignCertId();
      signStr = setSignXmlValue('CerID', cerId, signStr);
      signStr = setSignXmlValue('SignValue', signReturn, signStr);
    }
  } catch (err) {
    console.error(err.stack);
  }
  return signStr;
};

/**
 * 设置Xml报文中的签名值
 * @param {[string]} noteName [xml标签]
 * @param {[string]} value    [xml值]
 * @param {[string]} signStr  [签名xml报文]
 */
function setSignXmlValue(noteName, value, signStr) {
  var nodeStart = '<' + noteName + '>';
  var nodeEnd = '</' + noteName + '>';
  var shortNode = '<' + noteName + '/>';
  if (signStr.indexOf(nodeStart) !== -1 && signStr.indexOf(nodeEnd) !== -1) {
    // 包含完整noteName节点
  } else if (signStr.indexOf(shortNode) !== -1) {
    // 包含缩略的空noteName节点
    // 将<noteName/> 格式的节点 替换成<noteName></noteName>
    signStr = signStr.replace(signStr, nodeStart + nodeEnd);
  } else {
    // 不存在node节点
    // 检查Sign节点是否存在
    if (signStr.indexOf('<Sign>') !== -1 && signStr.indexOf('</Sign>') !== -1) {

    } else if (signStr.indexOf('<Sign/>') !== -1) {
      // 替换短节点
      signStr = signStr.replace('<Sign/>', '<Sign></Sign>');
    } else {
      // 插入空节点
      signStr = signStr.replace('</GPay>', '<Sign></Sign></GPay>');
    }
    var node = nodeStart + nodeEnd;
    signStr = signStr.replace('</Sign>', node + '</Sign>');
  }
  signStr = StringUtil.replaceValueByTag(noteName, value, signStr);
  return signStr;
}


/**
 * 对字符串进行验签
 * @param  {[string]} signedStr [已签名字符串]
 * @return {[boolean]}          [签名成功与否]
 */
exports.verify = function(signedStr) {
  // 1.判断 checkValue 的类型
  var valueType = checkSignStr(signedStr);
  // 2.验签处理
  if (valueType === XML_TYPE) {
    // 2.1 当checkValue为xml处理
    var signValue = StringUtil.getValueByTag('SignValue', signedStr);
    var header = StringUtil.getValueByTag('Header', signedStr);
    var body = StringUtil.getValueByTag('Body', signedStr);
    var sb = '<Header>' + header + '</Header>|<Body>' + body + '</Body>';
    // 验签
    return signVerify(sb, signValue);
  } else {

  }
  return false;
};

/**
 * 进行验签操作
 * @param  {[string]} dataStr   [原报文]
 * @param  {[string]} signValue [签名报文]
 * @return {[boolean]}          [验签成功与否]
 */
function signVerify(dataStr, signValue) {
  var isValid = false;
  try {
    CertificateCoder.init(BASE_DIR + ConfUtil.get('keystore.priKeyPath'), BASE_DIR + ConfUtil.get('keystore.pubKeyPath'));
    isValid = CertificateCoder.verify(dataStr, Base64Util.decode(signValue));
  } catch (e) {
    throw new Error(e);
  }
  return isValid;
}

/**
 * 检测字符串类型
 * 1.XML格式
 * 2.keyvalue格式
 * @param  {[string]} str [被验证字符串]
 * @return {[boolean]}       [是否符合XML或keyvalue格式]
 */
function checkSignStr(str) {
  str = str.trim();
  if ((str.startsWith('<?xml') || str.startsWith('<GPay>')) && str.endsWith('</GPay>')) {
    valueType = XML_TYPE;
  } else if (str.match(/[a-zA-Z]+[=]+&*/)) {
    valueType = KEYVALUE_TYPE;
  } else {
    throw new Error('暂时不支持非key=value与xml以外格式的字符串');
  }
  return valueType;
}
